<?php
/***********************************************************************
 * @package    	IvanEngine
 * @subpackage 	Core
 * @author     	Ivan <ivanzx@msn.com>
 * @created    	2010-05-16
 * @purpose	   	CDatabase is a base abstraction class that allows you to 
 * 				setup any type of database connection via a configuration file.
 ***********************************************************************/
if(defined("IVANENGINE_CORE_DATABASE_DATABASE"))
	die("Redefinition macro in :".__FILE__."(".__LINE__.")");
define("IVANENGINE_CORE_DATABASE_DATABASE", true);

require_once (dirname(__FILE__).'/../Object.php');
require_once (dirname(__FILE__).'/DBQueryResult.php');

abstract class CDatabase extends CObject 
{
	protected $m_settings	= array();
	protected $m_linkId		= null;
	protected $m_queryCount	= 0;
	protected $m_queryLog	= null;
	protected $m_lastResult	= null;
	protected $m_version	= '';
	
	public function __construct($dbhost, $dbuser, $dbpw, 
		$dbname = '', $charset = 'utf8', $pconnect = 0)
	{
		parent::__construct();
		
		$this->m_queryLog = new CVector();
		$this->m_settings = array(	
		'dbhost'   => $dbhost, 	'dbuser'   => $dbuser,
		'dbpw'     => $dbpw, 	'dbname'   => $dbname,
        'charset'  => $charset,	'pconnect' => $pconnect );
	}
	
	function __destruct() 
	{
		unset($this->m_queryLog);
		unset($this->m_settings);
		parent::__destruct();
	}
	
	// Connects to the database.
  	abstract function Connect();
  	
  	// Executes the shutdown procedure.
	abstract function Disconnect();
	
	abstract function Version();
	
	abstract function SelectDatabase($dbName);
	
	abstract function SetCharset($charset);
	
	abstract function Query($sql);
	
	abstract function LastAffectedRows();
	
	abstract function LastErrorMsg();
	
	abstract function LastErrorCode();
	
	abstract function LastInsertId();
	
	function QueryLog()
	{
		return $this->m_queryLog;
	}
	
	function QueryCount()
	{
		return $this->m_queryCount;
	}
	
	function Insert($table, array $fieldAndvalues)
	{
		$sql		= '';
		$tableInfo	= $this->Query('DESC '.$table, false);
		$fields 	= $values = array();
        foreach ($fieldAndvalues AS $key => $value)
        {
        	if ($tableInfo->IsExistsKey($key) == true)
			{
				$fields[] = $key;
				$values[] = "'" . $value . "'";
			}
		}
		$tableInfo->Clear();

		if (!empty($fields))
			$sql = 'INSERT INTO ' . $table . ' (' . implode(', ', $fields) . 
				') VALUES (' . implode(', ', $values) . ')';
		
		if ($sql)
            return $this->Query($sql);
        else
            return false;
	}
	
	function Update($table, $fieldAndvalues, $where = '')
	{
		$sql		= '';
		$tableInfo	= $this->Query('DESC '.$table, false);
		$fields 	= $values = array();
        foreach ($fieldAndvalues AS $key => $value)
        {
        	if ($tableInfo->IsExistsKey($key) == true)
			{
				$sets[] = $key . " = '" . $value . "'";
			}
		}
		$tableInfo->Clear();

		if (!empty($sets))
		{
			$sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $sets);
			if( $where ) $sql .= ' WHERE ' . $where;
		}
		
		if ($sql)
            return $this->Query($sql);
        else
            return false;
	}
	
	function Replace($table, $fieldAndValues, $where)
	{
		$tableInfo	= $this->Query('DESC '.$table);
		$tableIt	= $tableInfo->Begin();
		$primary_keys = array();
		while ($tableIt->IsValid())
		{
			$field_names[]	= $tableIt->Data()->At('Field');
			if ($tableIt->Data()->At('Key') == 'PRI')
            {
                $primary_keys[] = $tableIt->Data()->At('Field');
            }
		}

        $fields = $values = array();
        foreach ($field_names AS $value)
        {
            if (array_key_exists($value, $fieldAndValues) == true)
            {
                $fields[] = $value;
                $values[] = "'" . $fieldAndValues[$value] . "'";
            }
        }

        $sets = array();
        foreach ($fieldAndValues AS $key => $value)
        {
            if (array_key_exists($key, $fieldAndValues) == true)
            {
                if (is_int($value) || is_float($value))
                {
                    $sets[] = $key . ' = ' . $key . ' + ' . $value;
                }
                else
                {
                    $sets[] = $key . " = '" . $value . "'";
                }
            }
        }

        $sql = '';
        if (empty($primary_keys))
        {
            if (!empty($fields))
            {
                $sql = 'INSERT INTO ' . $table . ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')';
            }
        }
        else
        {
            if ($this->Version() >= '4.1')
            {
                if (!empty($fields))
                {
                    $sql = 'INSERT INTO ' . $table . ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')';
                    if (!empty($sets))
                    {
                        $sql .=  'ON DUPLICATE KEY UPDATE ' . implode(', ', $sets);
                    }
                }
            }
            else
            {
                if (empty($where))
                {
                    $where = array();
                    foreach ($primary_keys AS $value)
                    {
                        if (is_numeric($value))
                        {
                            $where[] = $value . ' = ' . $fieldAndValues[$value];
                        }
                        else
                        {
                            $where[] = $value . " = '" . $fieldAndValues[$value] . "'";
                        }
                    }
                    $where = implode(' AND ', $where);
                }

                if ($where && (!empty($sets) || !empty($fields)))
                {
                	$tempRt	= $this->Query("SELECT COUNT(*) FROM $table WHERE $where");
                	$tempRtA= $tempRt->RowIdx(0);
                    if (intval($tempRtA[0]) > 0)
                    {
                        if (!empty($sets))
                        {
                            $sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $sets) . ' WHERE ' . $where;
                        }
                    }
                    else
                    {
                        if (!empty($fields))
                        {
                            $sql = 'REPLACE INTO ' . $table . ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')';
                        }
                    }
                }
            }
        }

        if ($sql)
        {
            return $this->query($sql);
        }
        else
        {
            return false;
        }
	}
}


?>